package com.czl.myRabbitMq.mqClient;

import com.czl.myRabbitMq.commom.BinaryTransformTool;
import com.czl.myRabbitMq.commom.Consume;
import com.czl.myRabbitMq.commom.Request;
import com.czl.myRabbitMq.commom.Response;
import com.czl.myRabbitMq.commom.argument.*;
import com.czl.myRabbitMq.commom.returns.BasicReturns;
import com.czl.myRabbitMq.commom.returns.DescribeReturns;
import com.czl.myRabbitMq.mqServer.core.BasicProperties;
import com.czl.myRabbitMq.mqServer.core.ExchangeType;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Data
public class Channel {
    private String channelId;
    //表示当前是那个连接持有该信道
    private Connection connection;
    //用来存储服务器返回的消息对象  Key是消息的rid
    private ConcurrentHashMap<String, BasicReturns> returnMap = new ConcurrentHashMap<>();
    //同时规定每一个信道中的回调
    private Consume consume;
    public Channel(String channelId, Connection connection){
        this.channelId = channelId;
        this.connection = connection;
    }

    public void sendMessage(DescribeReturns describeReturns){
        returnMap.put(describeReturns.getRid(), describeReturns);
        //同时需要唤醒上述等待的线程
        synchronized (this) {
            notifyAll();
        }
    }

    private String getRidUUID(){
        return "R-" + UUID.randomUUID();
    }

    //这个方法用于客户端和服务器之间的通信的
    //用于告诉服务器 我们需要创建一个管道
    public boolean createChannel() throws IOException {
        BasicArguments basicArguments = new BasicArguments();
        basicArguments.setChannelId(channelId);
        basicArguments.setRid(getRidUUID());
        byte[] body = BinaryTransformTool.getBinaryData(basicArguments);

        Request request = new Request();
        request.setType(0x1);
        request.setLength(body.length);
        request.setBody(body);

        connection.writeRequest(request);
        //发送消息之后 我们阻塞等待服务器处理消息完毕 然后我们进行一个接受
        BasicReturns basicReturns = waitResult(basicArguments.getRid());
        log.info("创建信道成功" + basicArguments.getChannelId());
        return basicReturns.isOk();
    }
    //阻塞等待收到相应的服务器返回的消息
    private BasicReturns waitResult(String rid) {
        BasicReturns basicReturns = null;
        while ((basicReturns = returnMap.get(rid)) == null){
            synchronized (this){
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        //处理完毕之后需要将map中的内容删除掉
        returnMap.remove(rid);
        return basicReturns;
    }

    //关闭一个信道
    public boolean close() throws IOException {
        BasicArguments basicArguments = new BasicArguments();
        basicArguments.setRid(getRidUUID());
        basicArguments.setChannelId(channelId);
        byte[] body = BinaryTransformTool.getBinaryData(basicArguments);
        Request request = new Request();
        request.setType(0x2);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(basicArguments.getRid());
        log.info("删除信道成功" + basicArguments.getChannelId());
        return basicReturns.isOk();
    }

    //创建一个交换机
    public boolean exchangeDeclare(String exchangeName, ExchangeType exchangeType, boolean isDurable,
                                   boolean isAutoDelete, Map<String, Object> params) throws IOException {
        ExchangeDeclareArguments exchangeDeclareArguments = new ExchangeDeclareArguments();
        exchangeDeclareArguments.setExchangeName(exchangeName);
        exchangeDeclareArguments.setExchangeType(exchangeType);
        exchangeDeclareArguments.setDurable(isDurable);
        exchangeDeclareArguments.setAutoDelete(isAutoDelete);
        exchangeDeclareArguments.setParams(params);
        byte[] body = BinaryTransformTool.getBinaryData(exchangeDeclareArguments);

        Request request = new Request();
        request.setType(0x3);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(exchangeDeclareArguments.getRid());
        log.info("创建交换机成功" + exchangeName);
        return basicReturns.isOk();
    }

    //删除一个交换机
    public boolean deleteExchange(String exchangeName) throws IOException {
        DeleteExchangeArguments deleteExchangeArguments = new DeleteExchangeArguments();
        deleteExchangeArguments.setExchangeName(exchangeName);
        byte[] body = BinaryTransformTool.getBinaryData(deleteExchangeArguments);

        Request request = new Request();
        request.setType(0x4);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(deleteExchangeArguments.getRid());
        log.info("删除交换机成功" + exchangeName);
        return basicReturns.isOk();
    }

    //String queueName,boolean isDurable, boolean exclusive,
    //                                    boolean isAutoDelete,Map<String, Object> params
    //创建一个交换机
    public boolean QueueDeclare(String queueName, boolean isDurable, boolean exclusive,
                                boolean isAutoDelete, Map<String, Object> params) throws IOException {
        QueueDeclareArguments queueDeclareArguments = new QueueDeclareArguments();
        queueDeclareArguments.setQueueName(queueName);
        queueDeclareArguments.setDurable(isDurable);
        queueDeclareArguments.setExclusive(exclusive);
        queueDeclareArguments.setAutoDelete(isAutoDelete);
        queueDeclareArguments.setParams(params);
        byte[] body = BinaryTransformTool.getBinaryData(queueDeclareArguments);

        Request request = new Request();
        request.setType(0x5);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(queueDeclareArguments.getRid());
        log.info("创建队列成功" + queueName);
        return basicReturns.isOk();
    }

    //删除一个队列
    public boolean DeleteQueue(String queueName) throws IOException {
        DeleteQueueArguments deleteQueueArguments = new DeleteQueueArguments();
        deleteQueueArguments.setQueueName(queueName);
        byte[] body = BinaryTransformTool.getBinaryData(deleteQueueArguments);

        Request request = new Request();
        request.setType(0x6);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(deleteQueueArguments.getRid());
        log.info("删除队列成功" + queueName);
        return basicReturns.isOk();
    }

    //创建一个binding
    public boolean queueBinding(String exchangeName, String queueName, String bindingKey) throws IOException {
        QueueBindingArguments queueBindingArguments = new QueueBindingArguments();
        queueBindingArguments.setExchangeName(exchangeName);
        queueBindingArguments.setQueueName(queueName);
        queueBindingArguments.setBindingKey(bindingKey);
        byte[] body = BinaryTransformTool.getBinaryData(queueBindingArguments);

        Request request = new Request();
        request.setType(0x7);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(queueBindingArguments.getRid());
        log.info("创建绑定成功 exchangeName = " + exchangeName + "queueName = " + queueName);
        return basicReturns.isOk();
    }

    //销毁一个binding
    public boolean queueUnbinding(String exchangeName, String queueName) throws IOException {
        QueueUnbindingArguments queueUnbindingArguments = new QueueUnbindingArguments();
        queueUnbindingArguments.setExchangeName(exchangeName);
        queueUnbindingArguments.setQueueName(queueName);
        byte[] body = BinaryTransformTool.getBinaryData(queueUnbindingArguments);

        Request request = new Request();
        request.setType(0x8);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(queueUnbindingArguments.getRid());
        log.info("绑定删除成功 exchangeName = " + exchangeName + "queueName = " + queueName);
        return basicReturns.isOk();
    }

    //String exchangeName, String routineKey,
    //                                ExchangeType exchangeType, BasicProperties basicProperties,
    //                                byte[] body
    //发送一个Message
    public boolean basicPublish(String exchangeName, String routineKey, ExchangeType exchangeType,
                                BasicProperties basicProperties, byte[] message) throws IOException {
        BasicPublishArguments basicPublishArguments = new BasicPublishArguments();
        basicPublishArguments.setExchangeName(exchangeName);
        basicPublishArguments.setExchangeType(exchangeType);
        basicPublishArguments.setRoutineKey(routineKey);
        basicPublishArguments.setBasicProperties(basicProperties);
        basicPublishArguments.setBody(message);
        byte[] body = BinaryTransformTool.getBinaryData(basicPublishArguments);

        Request request = new Request();
        request.setType(0x9);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(basicPublishArguments.getRid());
        log.info("推送消息成功");
        return basicReturns.isOk();
    }

    //订阅一个消费者
    public boolean basicConsume(String consumeTag, String queueName, boolean autoACK) throws IOException {
        BasicConsumeArguments basicConsumeArguments = new BasicConsumeArguments();
        basicConsumeArguments.setConsumeTag(consumeTag);
        basicConsumeArguments.setQueueName(queueName);
        basicConsumeArguments.setAutoACK(autoACK);
        byte[] body = BinaryTransformTool.getBinaryData(basicConsumeArguments);

        Request request = new Request();
        request.setType(0xa);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(basicConsumeArguments.getRid());
        log.info("订阅消费者成功 consumeTag = " + consumeTag);
        return basicReturns.isOk();
    }
    //返回ACK调用删除逻辑
    public boolean BasicACK(String queueName, String messageId) throws IOException {
        BasicACKArguments basicACKArguments = new BasicACKArguments();
        basicACKArguments.setQueueName(queueName);
        basicACKArguments.setMessageId(messageId);
        byte[] body = BinaryTransformTool.getBinaryData(basicACKArguments);

        Request request = new Request();
        request.setType(0xb);
        request.setLength(body.length);
        request.setBody(body);
        connection.writeRequest(request);

        BasicReturns basicReturns = waitResult(basicACKArguments.getRid());
        log.info("成功返回ACK");
        return basicReturns.isOk();
    }

}
